using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using System.IO.IsolatedStorage;
using System.Xml.Serialization;

using LevelData;
using GGJ11.Resources;

namespace GGJ11
{
    public enum WinLoseState
    {
        Lose,
        None
    }

    public class MainGameComponent : Microsoft.Xna.Framework.DrawableGameComponent
    {
        SpriteBatch spriteBatch;
        RenderingState renderingState;
        GameState gameState;
        SoundManager soundState;
        Level level;
        
        public event Action Back;
        public event Action Win;
        public event Action Lose;

#if WINDOWS_PHONE
        IsolatedStorageFile IS = IsolatedStorageFile.GetUserStoreForApplication();
#endif
#if WINDOWS
        IsolatedStorageFile IS = IsolatedStorageFile.GetUserStoreForDomain();
#endif
        string savePath = "./currentGame.sav";
        string savePathNumLevel = "./currentNumLevel.sav";

        public MainGameComponent(MainGame game, bool forceNewGame, int selectedLevel)
            : base(game)
        {
            TouchPanel.EnabledGestures = GestureType.Tap;

            if (forceNewGame)
            {
                Game.Content.Unload();
                LoadNextLevel(true, selectedLevel);
            }
            else
            {
                level = ResumeState();
                if (level.playerLevel.life == 0)
                {
                    ReloadLevel();
                }
            }

            Game.Services.AddService(typeof(Level), level);
            gameState = new GameState(Content);
            renderingState = new RenderingState(Content);
            soundState = new SoundManager(Content);
        }

        private void ReloadLevel()
        {
            int numCurrentLevel = level.numLevel;

            Content.Unload();

            level = Content.Load<Level>("Level/level" + numCurrentLevel);
            level.storyMode = false;
        }

        ContentManager Content { get { return Game.Content; } }

        protected override void LoadContent()
        {
            base.LoadContent();
        }


        public override void Initialize()
        {
            spriteBatch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;

            base.Initialize();
        }

        //resume level
        private Level ResumeState()
        {
            if(IS.FileExists(savePath))
            {
            Level level = null;

            using (var saveFile = IS.OpenFile(savePath, System.IO.FileMode.Open))
            {
                var deserializer = new XmlSerializer(typeof(Level));
                level = deserializer.Deserialize(saveFile) as Level;
            }
            IS.DeleteFile(savePath);
            return level;
            }

            return null;
        }


        private int NumLevelState()
        {
            object numLevel = 0;
            if (IS.FileExists(savePathNumLevel))
            {
                using (var saveFile = IS.OpenFile(savePathNumLevel, System.IO.FileMode.Open))
                {
                    var deserializer = new XmlSerializer(typeof(int));
                    numLevel = deserializer.Deserialize(saveFile);
                }
            }

            return (int)numLevel;
        }


        //save game
        private void SaveGameState()
        {
            try
            {
                using (var saveFile = IS.CreateFile(savePath))
                {
                    var serializer = new XmlSerializer(typeof(Level));
                    serializer.Serialize(saveFile, level);
                }

                using (var saveFile = IS.CreateFile(savePathNumLevel))
                {
                    var serializer = new XmlSerializer(typeof(int));
                    serializer.Serialize(saveFile, level.numLevel);
                }
            }
            catch (Exception)
            {
            }
        }


        //Main update
        public override void Update(GameTime gameTime)
        {
            level.totalGameTime += gameTime.ElapsedGameTime.TotalSeconds;
            UpdateMainGame(gameTime);
            base.Update(gameTime);
        }

        private void UpdateMainGame(GameTime gameTime)
        {
            //call update for the game
            gameState.Update(gameTime);

            //check if player die
            if (level.playerLevel.life <= 0)
            {
                //restore player life and points
                SaveGameState();
                soundState.StopMusic();
                level.totalGameTime = 0;

                //remove service
                Game.Services.RemoveService(typeof(Level));

                //invoke end menu
                Lose();
            }
           
            //check if player end level
            if (level.playerLevel.exit)
            {
                soundState.StopMusic();
                level.playerLevel.exit = false;
                SaveGameState();
                LoadNextLevel(false, 0);
            }

            //check if back is pressed
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                this.Enabled = false;

                //show message for save file
                Guide.BeginShowMessageBox(Strings.ConfirmExit, Strings.ConfirmExitMessage,
                  new[] { Strings.Yes, Strings.No }, 0, MessageBoxIcon.Alert, new AsyncCallback(result =>
                  {
                      var dialogResult = Guide.EndShowMessageBox(result);
                      this.Enabled = true;
                      if (dialogResult.HasValue && dialogResult.Value == 0)
                      {
                          if (Back != null)
                          {
                              Game.Services.RemoveService(typeof(Level));
                              SaveGameState();
                              Back();
                          }
                      }
                  }
                  ), null);
            }

            //update sound
             soundState.updateSounds();
        }

        //load next level when player arrive at the end of level
        public void LoadNextLevel(bool newGame, int selectedLevel)
        {
            //check if this is a new game
            if (newGame)
            {
                level = Content.Load<Level>("Level/level" + selectedLevel.ToString());
                level.soundList.Add(SoundType.musicStop);
                level.soundList.Add(SoundType.storyPlay);
            }
            else
            {
                //calculate new level index
                int numNextLevel = level.numLevel + 1;

                //remove old level from service
                Game.Services.RemoveService(typeof(Level));

                //load new level
                if (numNextLevel < 13)
                {
                    Level newLevel = Content.Load<Level>("Level/level" + numNextLevel);

                    //set player life and points from old level
                    newLevel.playerLevel.life = level.playerLevel.life;
                    newLevel.playerLevel.points = level.playerLevel.points;
                    newLevel.playerLevel.health = level.playerLevel.health;
                    newLevel.totalGameTime = level.totalGameTime;


                    //update level variable
                    level = newLevel;

                    //add newlevel into services
                    Game.Services.AddService(typeof(Level), level);

                    //update level services from gameState and renderingState
                    gameState.UpdateLevelService(Content);
                    renderingState.UpdateLevelService(Content);
                    soundState.UpdateLevelService(Content);
                    level.soundList.Add(SoundType.musicStop);
                    level.soundList.Add(SoundType.storyPlay);
                }
                else
                {
                    //WIN
                    Win();
                }
            }
        }

        //draw method
        public override void Draw(GameTime gameTime)
        {
            renderingState.Draw(gameTime, spriteBatch);
            base.Draw(gameTime);
        }
    }
}
